﻿using System;
using System.Net;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using ElectronicShoppingMall.Service.Services.Enterprise;
using ElectronicShoppingMall.Web.Back.DTOS;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;

namespace ElectronicShoppingMall.Web.Back.Authorization
{
    public class CustomOAuthProvider : OAuthAuthorizationServerProvider
    {
        public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var account = context.UserName;
            var password = context.Password;
            int userId;
            int employeeId;
            string userAvatar;
            string nickname;
            if (!CheckCredential(account, password, out userId, out employeeId, out userAvatar, out nickname))
            {
                context.SetError("invalid_grant", "The user name or password is incorrect");
                context.Rejected();
                return Task.FromResult<object>(null);
            }
            var ticket = new Microsoft.Owin.Security.AuthenticationTicket(SetClaimsIdentity(context, userId, account, employeeId, userAvatar, nickname), new AuthenticationProperties());
            context.Validated(ticket);
            return Task.FromResult<object>(null);
        }

        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
            return Task.FromResult<object>(null);
        }

        private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context, int userid, string account, int employeeId, string userAvatar, string nickname)
        {
            var identity = new ClaimsIdentity("JWT");
            identity.AddClaim(new Claim("userId", userid + ""));
            identity.AddClaim(new Claim("account", account));
            identity.AddClaim(new Claim("employeeId", employeeId + ""));
            identity.AddClaim(new Claim("userAvatar", userAvatar));
            identity.AddClaim(new Claim("nickname", nickname));
            return identity;
        }

        private static bool CheckCredential(string account, string password, out int userId, out int employeeId, out string userAvatar, out string nickname)
        {
            EmployeeUserService _service = new EmployeeUserService();
            var success = false;            // 用户名和密码验证
            try
            {
                var user = _service.Login(account, password, GetClientIPv4Address());
                EmployeeUserDTO currentUser = new EmployeeUserDTO()
                {
                    Name = user.Name,
                    UserId = user.UserId,
                    EmployeeId = user.EmployeeId,
                    UserAvatar = user.UserAvatar
                };
                userId = currentUser.UserId;
                employeeId = currentUser.EmployeeId;
                userAvatar = currentUser.UserAvatar;
                nickname = currentUser.Name;
                success = true;
            }
            catch
            {
                userId = 0;
                employeeId = 0;
                userAvatar = "";
                nickname = "";
                success = false;
            }
            return success;
        }

        private static string GetClientIPv4Address()
        {
            string ipv4 = String.Empty;

            foreach (IPAddress ip in Dns.GetHostAddresses(GetClientIP()))
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    ipv4 = ip.ToString();
                    break;
                }
            }

            if (ipv4 != String.Empty)
            {
                return ipv4;
            }
            // 利用 Dns.GetHostEntry 方法，由获取的 IPv6 位址反查 DNS 纪录，
            // 再逐一判断何者为 IPv4 协议，即可转为 IPv4 位址。
            foreach (IPAddress ip in Dns.GetHostEntry(GetClientIP()).AddressList)
            //foreach (IPAddress ip in Dns.GetHostAddresses(Dns.GetHostName()))
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    ipv4 = ip.ToString();
                    break;
                }
            }

            return ipv4;
        }
        private static string GetClientIP()
        {
            if (null == HttpContext.Current.Request.ServerVariables["HTTP_VIA"])
            {
                return HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            }
            else
            {
                return HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            }
        }
    }
}